home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / doom / axxwar_1.zip / SOURCES / GRAPPLE.QC < prev    next >
Text File  |  1997-02-27  |  13KB  |  421 lines

  1. // AxxWars 0.8
  2.  
  3. float() crandom;    // AXXGR
  4.  
  5.  
  6. /*
  7. =============
  8. Reset_Grapple
  9. =============
  10. */
  11. void (entity rhook) Reset_Grapple =
  12. {      sound (rhook.owner, CHAN_WEAPON, "weapons/bounce2.wav", 1, ATTN_NORM);
  13.         rhook.owner.on_hook = FALSE;
  14.         rhook.owner.hook_out = FALSE;
  15.         rhook.owner.fire_held_down = FALSE;
  16.         rhook.owner.weaponframe = 0;
  17.  
  18.         rhook.think = SUB_Remove;
  19.         rhook.nextthink = time;
  20. };
  21.  
  22. /*
  23. ==============
  24. Remove_Grapple
  25. ==============
  26. */
  27. void (entity rhook) Remove_Grapple =
  28. {
  29.         sound (rhook.owner, CHAN_WEAPON, "weapons/bounce2.wav", 1, ATTN_NORM);
  30.       centerprint (rhook.owner, "Your harpoon was pulled away!");
  31.         rhook.owner.on_hook = FALSE;
  32.         rhook.owner.hook_out = TRUE;
  33.       rhook.owner.hook_gone = TRUE;    
  34.         rhook.owner.fire_held_down = FALSE;
  35.         rhook.owner.weaponframe = 0;
  36.  
  37.         rhook.think = SUB_Remove;
  38.         rhook.nextthink = time;
  39. };
  40.  
  41. /*
  42. ===========
  43. RemoveChain
  44. ===========
  45. */
  46. void () Remove_Chain =
  47. {
  48.                 self.think = SUB_Remove;
  49.                 self.nextthink = time;
  50.  
  51.                 if (self.goalentity)
  52.                 {
  53.                         self.goalentity.think = SUB_Remove;
  54.                         self.goalentity.nextthink = time;
  55.  
  56.                         if (self.goalentity.goalentity)
  57.                         {
  58.                                 self.goalentity.goalentity.think = SUB_Remove;
  59.                                 self.goalentity.goalentity.nextthink = time;
  60.                         }
  61.                 }
  62.                 
  63. };
  64.  
  65. /*
  66. =============
  67. Grapple_Track
  68. =============
  69. */
  70.  
  71. void () Grapple_Track =
  72. {
  73.         local   vector  spray;
  74.  
  75.         // Release dead targets
  76.         if ((self.enemy.classname == "player") || (self.enemy.classname == "cbot")) 
  77.         if (self.enemy.health <= 0)    
  78.                 {
  79.                     self.owner.on_hook = FALSE;
  80.                     self.owner.attack_finished = time +0.50;
  81.                 }
  82.  
  83.         // drop the hook if owner is dead or has released the button
  84.         if (!self.owner.on_hook || self.owner.health <= 0)
  85.         {
  86.                 Reset_Grapple (self);
  87.                 return;
  88.         }
  89.  
  90.         // bring the pAiN!
  91.         if ((self.enemy.classname == "player") || (self.enemy.classname == "cbot"))
  92.         {        
  93.             // move the hook along with the player.  It's invisible, but
  94.             // we need this to make the sound come from the right spot
  95.             setorigin(self, self.enemy.origin);
  96.             
  97.             sound (self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM);
  98.             Remove_Chain;
  99.             Remove_Grapple (self);
  100.             return;
  101.  
  102.             T_Damage (self.enemy, self, self.owner, 1);
  103.             makevectors (self.v_angle);
  104.             spray_x = 100 * crandom();
  105.             spray_y = 100 * crandom();
  106.             spray_z = 100 * crandom() + 50;
  107.             particle (self.enemy.origin, spray, 73, 20);// avoid a call to spawnblood
  108.               
  109.       }
  110.  
  111.         // If the hook is not attached to the player, constantly copy
  112.         // copy the target's velocity. Velocity copying DOES NOT work properly
  113.         // for a hooked client. 
  114.         if ((self.enemy.classname != "player") && (self.enemy.classname != "cbot"))
  115.                 self.velocity = self.enemy.velocity;
  116.  
  117.         self.nextthink = time + 0.1;
  118. };
  119.  
  120. /*
  121. ========
  122. MakeLink
  123. ========
  124. */
  125. entity (float head) MakeLink =
  126. {
  127.         newmis = spawn ();
  128.  
  129.         newmis.movetype = MOVETYPE_FLYMISSILE;
  130.         newmis.solid = SOLID_NOT;
  131.         newmis.owner = self;// SELF is the hook!
  132.  
  133.         newmis.avelocity = '200 200 200';
  134.  
  135.         setmodel (newmis, "progs/bit.mdl");
  136.         setorigin (newmis, self.origin);
  137.         setsize (newmis, '0 0 0' , '0 0 0');
  138.  
  139.         return  newmis;
  140. };
  141.  
  142. /*
  143. ============
  144. Update_Chain
  145. ============
  146. */
  147. void () Update_Chain =
  148. {
  149.         local   vector  temp;
  150.  
  151.         if (!self.owner.hook_out)
  152.         {
  153.                 self.think = Remove_Chain;
  154.                 self.nextthink = time;
  155.                 return;
  156.         }
  157.  
  158.         temp = (self.owner.hook.origin - self.owner.origin);
  159.  
  160.         // These numbers are correct assuming 3 links.
  161.         // 4 links would be *20 *40 *60 and *80
  162.         setorigin (self, self.owner.origin + temp * 0.25);
  163.         setorigin (self.goalentity, self.owner.origin + temp * 0.5);
  164.         setorigin (self.goalentity.goalentity, self.owner.origin + temp * 0.75);
  165.  
  166.         self.nextthink = time + 0.1;
  167. };
  168.  
  169. /*
  170. ===========
  171. Build_Chain
  172. ===========
  173. */
  174. void () Build_Chain =
  175. {
  176.         self.goalentity = MakeLink();
  177.         self.goalentity.think = Update_Chain;
  178.         self.goalentity.nextthink = time - 0.1;
  179.         self.goalentity.owner = self.owner;
  180.  
  181.         self.goalentity.goalentity = MakeLink();
  182.         self.goalentity.goalentity.goalentity = MakeLink();
  183. };
  184.  
  185. /*
  186. ==============
  187. Check_Overhead
  188. ==============
  189. */
  190. float () Check_Overhead =
  191. {
  192.         local   vector  src;
  193.         local   vector  end;
  194.  
  195.         makevectors (self.owner.angles);
  196.  
  197.         // The following comparisons could be optimized by doing away with
  198.         // SRC and END, and plugging the values directly into the traceline
  199.         // function calls. Using SRC and END made debugging easier. You
  200.         // decide if it's worth it.
  201.  
  202.         // quick check right above head
  203.         src = self.owner.origin - '0 0 24';
  204.         end = self.owner.origin - '0 0 24';
  205.         traceline (src, end, FALSE, self.owner);
  206.         if (trace_fraction != 1.0)
  207.                 return FALSE;
  208.  
  209.         src = self.owner.origin - '0 0 24' - v_forward * 16;
  210.         end = self.owner.origin - '0 0 24' - v_forward * 16 + '0 0 58';
  211.         traceline (src, end, FALSE, self.owner);
  212.         if (trace_fraction != 1.0)
  213.                 return FALSE;
  214.  
  215.         src = self.owner.origin - '0 0 24' + v_forward * 16;
  216.         end = self.owner.origin - '0 0 24' + v_forward * 16 + '0 0 58';
  217.         traceline (src, end, FALSE, self.owner);
  218.         if (trace_fraction != 1.0)
  219.                 return FALSE;
  220.  
  221.         src = self.owner.origin - '0 0 24' - v_right * 16;
  222.         end = self.owner.origin - '0 0 24' - v_right * 16 + '0 0 58';
  223.         traceline (src, end, FALSE, self.owner);
  224.         if (trace_fraction != 1.0)
  225.                 return FALSE;
  226.  
  227.         src = self.owner.origin - '0 0 24' + v_right * 16;
  228.         end = self.owner.origin - '0 0 24' + v_right * 16 + '0 0 58';
  229.         traceline (src, end, FALSE, self.owner);
  230.         if (trace_fraction != 1.0)
  231.                 return FALSE;
  232.  
  233.         return TRUE;
  234. };
  235.  
  236.  
  237. /*
  238. ==============
  239. Anchor_Grapple
  240. ==============
  241. */
  242. void () Anchor_Grapple =
  243. {
  244.         local   float   test;
  245.  
  246.         if (other == self.owner)
  247.                 return;
  248.  
  249.         // DO NOT allow the grapple to hook to any projectiles, no matter WHAT!
  250.         // if you create new types of projectiles, make sure you use one of the
  251.         // classnames below or write code to exclude your new classname so
  252.         // grapples will not stick to them.
  253.         if (other.classname == "missile" || other.classname == "grenade" || 
  254.             other.classname == "spike" || other.classname == "hook"
  255.             || other.classname == "pipebomb" )
  256.             return;
  257.  
  258.         // Don't stick the the sky.
  259.         if (pointcontents(self.origin) == CONTENT_SKY)
  260.         {
  261.                 Reset_Grapple (self);
  262.                 return;
  263.         }
  264.  
  265.         if ((other.classname == "player") || (other.classname == "cbot"))
  266.         {
  267.                 // glance off of teammates
  268.                 // if (other.steam == self.owner.steam)
  269.                 // return;
  270.             
  271.                 sound (self, CHAN_WEAPON, "player/axhit1.wav", 1, ATTN_NORM);
  272.                 T_Damage (other, self, self.owner, 25);
  273.  
  274.                 // make hook invisible since we will be pulling directly
  275.                 // towards the player the hook hit. Quakeworld makes it
  276.                 // too quirky to try to match hook's velocity with that of
  277.                 // the client that it hit. 
  278.         
  279.                     setmodel (self, "");
  280.         }
  281.         else if ((other.classname != "player") && (other.classname != "cbot"))
  282.         {
  283.                 sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  284.  
  285.                 // One point of damage inflicted upon impact. Subsequent
  286.                 // damage will only be done to PLAYERS... this way secret
  287.                 // doors and triggers will only be damaged once.
  288.                 if (other.takedamage)
  289.                         T_Damage (other, self, self.owner, 1);
  290.  
  291.                 self.velocity = '0 0 0';
  292.                 self.avelocity = '0 0 0';
  293.       }
  294.  
  295.         // conveniently clears the sound channel of the CHAIN1 sound,
  296.         // which is a looping sample and would continue to play. Tink1 is
  297.         // the least offensive choice, ass NULL.WAV loops and clogs the
  298.         // channel with silence
  299.         sound (self.owner, CHAN_WEAPON, "weapons/tink1.wav", 1, ATTN_NORM);
  300.  
  301.         if (!self.owner.button0)
  302.         {
  303.                 Reset_Grapple (self);
  304.                 return;
  305.         }
  306.  
  307.         // our last chance to avoid being picked up off of the ground.
  308.         // check over the client's head to make sure there is one unit
  309.         // clearance so we can lift him off of the ground.
  310.         test = Check_Overhead ();
  311.         if (!test)
  312.         {
  313.                 Reset_Grapple (self);
  314.                 return;
  315.         }
  316.  
  317.         self.owner.on_hook = TRUE;
  318.  
  319.         if (self.owner.flags & FL_ONGROUND)
  320.         {
  321.                 self.owner.flags = self.owner.flags - FL_ONGROUND;
  322.                 setorigin(self.owner,self.owner.origin + '0 0 1');
  323.         }
  324.  
  325.      //   sound (self.owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM);
  326.  
  327.         // CHAIN2 is a looping sample. Use LEFTY as a flag so that client.qc
  328.         // will know to only play the tink sound ONCE to clear the weapons
  329.         // sound channel. (Lefty is a leftover from AI.QC, so I reused it to
  330.         // avoid adding a field)
  331.         self.owner.lefty = TRUE;
  332.  
  333.         self.enemy = other;// remember this guy!
  334.         self.think = Grapple_Track;
  335.         self.nextthink = time;
  336.         self.solid = SOLID_NOT;
  337.         self.touch = SUB_Null;
  338. };
  339.  
  340.  
  341. /*
  342. =============
  343. Throw_Grapple
  344. =============
  345. */
  346. void () Throw_Grapple =
  347. {
  348.         sound (self, CHAN_WEAPON, "tw/twharp.wav", 1, ATTN_NORM); // ThunderWalker Change New sound for Harpoon gun
  349.  
  350.         if (self.hook_out)// reject subsequent calls from player.qc
  351.                 return;
  352.  
  353.  
  354. //        msg_entity = self;
  355. //    WriteByte (MSG_ONE, SVC_SMALLKICK);
  356.  
  357.         newmis = spawn();
  358.         newmis.movetype = MOVETYPE_FLYMISSILE;
  359.         newmis.solid = SOLID_BBOX;
  360.         newmis.owner = self;// newmis belongs to me
  361.         self.hook = newmis;// This is my newmis
  362.         newmis.classname = "hook";
  363.  
  364.         makevectors (self.v_angle);
  365.         newmis.velocity = v_forward * 1000;
  366.         newmis.angles = vectoangles(newmis.velocity); // ThunderWalker Change made missle point in direction shot
  367.  
  368.  
  369.         newmis.touch = Anchor_Grapple;
  370.         newmis.think = Build_Chain;
  371.         newmis.nextthink = time + 0.1;// don't jam newmis and links into same packet
  372.  
  373.         setmodel (newmis,"progs/twharp.mdl"); // ThunderWalker Change the harpoon model
  374.         setorigin (newmis, self.origin + v_forward * 16 + '0 0 16');
  375.         setsize(newmis, '0 0 0' , '0 0 0 ');
  376.  
  377.         self.hook_out = TRUE;
  378.         self.fire_held_down = TRUE;
  379. };
  380.  
  381. /*
  382. ===============
  383. Service_Grapple
  384. ===============
  385. */
  386. void () Service_Grapple =
  387. {
  388.         local   vector  hook_dir;
  389.  
  390.         // drop the hook if player lets go of button
  391.         if (!self.button0)
  392.         {
  393.                 self.fire_held_down = FALSE;
  394.                 if (self.weapon == IT_GRAPPLE)
  395.                 Reset_Grapple (self.hook);
  396.         }
  397.         // If hooked to a player, track them directly!
  398.         if ((self.hook.enemy.classname == "player") || (self.hook.enemy.classname == "cbot"))
  399.                 hook_dir = (self.hook.enemy.origin - self.origin);
  400.         // else, track to hook
  401.         else if ((self.hook.enemy.classname != "player") && (self.hook.enemy.classname != "cbot"))
  402.                 hook_dir = (self.hook.origin - self.origin);
  403.  
  404.         self.velocity = normalize(hook_dir) * 750;
  405.         if ( vlen(hook_dir) <= 100 && self.lefty)// cancel chain sound
  406.         {
  407.                 // If there is a chain, ditch it now. We're
  408.                 // close enough. Having extra entities lying around
  409.                 // is never a good idea.
  410.                 if (self.hook.goalentity)
  411.                 { 
  412.                         self.hook.goalentity.think = Remove_Chain;
  413.                         self.hook.goalentity.nextthink = time;
  414.                 }
  415.  
  416.     //    sound(self, CHAN_WEAPON, "weapons/chain3.wav", 1, ATTN_NORM);
  417.         self.lefty = FALSE;// we've reset the sound channel.
  418.         }
  419. };
  420.  
  421.